package org.sensornet2010.alpha;

import java.util.Date;

import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Form;
import javax.microedition.lcdui.StringItem;
import javax.microedition.lcdui.TextBox;
import javax.microedition.media.Manager;
import javax.microedition.media.Player;
import javax.microedition.midlet.MIDlet;
import javax.microedition.midlet.MIDletStateChangeException;

/*
 * NAMING POLICIES:
 * 
 *  showXXXDisplay() synchronous  
 *  startXXXAction() asynchronous action
 *  updateXXXDisplay() synchronous
 *  
 *  xxxCommand  
 */

public class AlphaMidlet extends MIDlet  implements CommandListener {
	
	// Commands
	private Command exitCommand;
	private Command initializeCommand;
	private Command runCommand;
	
	// GUI components
	private Display		display; 				// The display for this MIDlet
	private StringItem 	statusText;				// Status information text
	private StringItem 	initializationStatus;	// 
	
	private RemoteServer 	server;
	private SoundRecorder	soundRecorder;

	// debug information
	private int 			counter;
	private Date			loopStartDate;

	public AlphaMidlet() {
		this.exitCommand = new Command("Exit", Command.EXIT, 1);
		this.initializeCommand = new Command("Initialize", Command.SCREEN, 1);
		this.runCommand = new Command("Run", Command.SCREEN, 1);
		this.display = Display.getDisplay(this);
		this.statusText = new StringItem("Status", null);
		this.initializationStatus = new StringItem("Info:", null);
	}

	protected void destroyApp(boolean unconditional) {
		// throws MIDletStateChangeException {
		// TODO Auto-generated method stub
	}

	protected void pauseApp() {
		// TODO Auto-generated method stub
	}

	protected void startApp() throws MIDletStateChangeException {
		this.showWelcomeDisplay();
	}

	public void commandAction(Command c, Displayable d) {
		if (c == exitCommand) {
			destroyApp(false);
			notifyDestroyed();
		} else if (c == this.initializeCommand) {
			this.showInitializationDisplay();
			this.startInitialization();
		} else if (c == this.runCommand) {
			this.showRunningLoopDisplay();
			this.startLoop();
		}
	}
	
	private void showErrorDisplay(Exception exception){
		// GUI components
		Form f = new Form("Error");
		f.append(exception.getMessage() + "\n");
		// GUI commands
		f.addCommand(this.exitCommand);
		f.setCommandListener(this);
		//
		display.setCurrent(f);
	}
	
	private void showWelcomeDisplay(){
		// GUI components
		Form f = new Form("Welcome");
		StringItem txt = new StringItem("This midlet", " captures audio continuously and the data is sent to the HTTP server.");
		f.append(txt);
		f.append("The initialization checks device capabilities (audio capture, server)");
		// GUI commands
		f.addCommand(this.initializeCommand);
		f.addCommand(this.exitCommand);
		f.setCommandListener(this);
		//
		display.setCurrent(f);
	}

	private void showInitializationDisplay(){
		// GUI components
		Form f = new Form("Initialization");
		f.append("Testing audio and internet connection\n");
		this.initializationStatus.setText("...");
		f.append(this.initializationStatus);
		// GUI commands
		f.addCommand(this.exitCommand);
		f.setCommandListener(this);
		//
		display.setCurrent(f);
	}

	private void showLoopDisplay(){
		// GUI components
		Form f = new Form("Loop");
		f.append("Execute Run to start the application\n");
		f.append("Server:" + Configuration.SERVER_URL + "\n");
		f.append("Recording duration:" + Configuration.RECORDING_DURATION/1000+ " seconds\n");
		f.append("Recording each:" + Configuration.RECORDING_INTERVAL + " seconds\n");
		// GUI commands
		f.addCommand(this.runCommand);
		f.addCommand(this.exitCommand);
		f.setCommandListener(this);
		//
		display.setCurrent(f);
	}
	private void showRunningLoopDisplay(){
		// GUI components
		Form f = new Form("RunningLoop");
		f.append("Running");
		this.statusText.setText("Running");
		f.append(this.statusText);
		// GUI commands
		f.addCommand(this.exitCommand);
		f.setCommandListener(this);
		//
		display.setCurrent(f);
	}
	
	private void startInitialization(){
		Thread t = new Thread(new Runnable() {
			public void run() {
				try {
					initialization();
					Thread.sleep(1000);
					showLoopDisplay();
				} catch (Exception e) {
					showErrorDisplay(e);
				};
			}
		});
		t.start();
	}
	private void startLoop() {
		this.loopStartDate = new Date();
		Thread t = new Thread(new Runnable() {
			public void run() {
				try {
					while(true){
						loop();
						Thread.sleep(Configuration.RECORDING_INTERVAL*1000);
					}
				} catch (Exception e) {
					showErrorDisplay(e);
				};
			}
		});
		t.start();
	}
	
	void initialization(){
		server = new RemoteServer(Configuration.SERVER_URL);
		soundRecorder = new SoundRecorder(Configuration.RECORDING_DURATION);
		String info = "";
		// test audio capture
		byte[] sound = this.soundRecorder.record();
		info+= "Recorded sound " + sound.length + "\n";
		this.initializationStatus.setText(info);
		// test server connection
		String data = this.server.getStatus();
		info = "Connected to server:\n status=" + data;
		this.initializationStatus.setText(info);
	}
	void loop(){
		counter++;
		Date date = new Date();
		try {
			// audio capture
			byte[] sound = this.soundRecorder.record();
			// audio processing
			SensorData data = new SensorData(Configuration.SENSOR_ID, sound);
			// send data to server
			this.server.sendData(data);
		} catch (Exception e) {
			e.printStackTrace();
		}
		// global debug info
		Runtime runt=Runtime.getRuntime();
		long freeMemory = runt.freeMemory();
		String globalInfo = "Started at: " + this.loopStartDate.toString() + " completed:" + counter +"\nFree memory:" +freeMemory;
		this.statusText.setText("done..." + date.toString() + "\n" + globalInfo);
		
	}

	
	
}
